#pragma once
#include <math.h>
#include <d3d9.h>

/**
 * Klasa wektora 3D
 *
 * @author Krzysztof Klein
 * @version 0.1
 */
class Vector
{

	// @{
	/**
	 * Wspolrzedna wektora
	 */
	float x, y, z;
	// @}

public:

	/**
	 * Konstruktor domyslny
	 */
	Vector() : x(0), y(0), z(0) { }

	/**
	 * Konstruktor z wspolrzednych kartezjanskich
	 */
	Vector(float x, float y, float z) : x(x), y(y), z(z) { }

//#ifdef D3DVECTOR_DEFINED
	/**
	 * Konstruktor z wektora Direct3D
	 */
	Vector(const D3DVECTOR &v) : x(v.x), y(v.y), z(v.z) { }
//#endif

	// @{
	/**
	 * Operator arytmetyczny
	 */
	Vector operator+(const Vector &v) const { return Vector(x+v.x, y+v.y, z+v.z); }
	Vector& operator+=(const Vector &v) { x+=v.x; y+=v.y; z+=v.z; return *this; }
	Vector operator-(const Vector &v) const { return Vector(x-v.x, y-v.y, z-v.z); }
	Vector& operator-=(const Vector &v) { x-=v.x; y-=v.y; z-=v.z; return *this; }
	Vector operator*(const Vector &v) const { return Vector(x*v.x, y*v.y, z*v.z); }
	Vector& operator*=(const Vector &v) { x*=v.x; y*=v.y; z*=v.z; return *this; }
	Vector operator/(const Vector &v) const { return Vector(x/v.x, y/v.y, z/v.z); }
	Vector& operator/=(const Vector &v) { x/=v.x; y/=v.y; z/=v.z; return *this; }
	Vector operator*(float t) const { return Vector(x*t, y*t, z*t); }
	Vector& operator*=(float t) { x*=t; y*=t; z*=t; return *this; }
	Vector operator/(float t) const { return Vector(x/t, y/t, z/t); }
	Vector& operator/=(float t) { x/=t; y/=t; z/=t; return *this; }
	Vector operator-() const { return Vector(-x, -y, -z); }
	// @}


	// @{
	/**
	 * Operator porownania
	 */
	bool operator<=(const Vector &v) const { return x<=v.x && y<=v.y && z<=v.z;}
	bool operator<(const Vector &v) const { return x<v.x && y<v.y && z<v.z;}
	bool operator>=(const Vector &v) const { return x>=v.x && y>=v.y && z>=v.z;}
	bool operator>(const Vector &v) const { return x>v.x && y>v.y && z>v.z;}
	// @}


	/**
	 * Normalizuje wektor
	 *
	 * @return Znormalizowany wektor
	 */
	Vector& normalize() {*this /= getLength(); return *this; }
	Vector normalized() const {return *this / getLength(); }
	

	/**
	 * Interpoluje wektor
	 *
	 * @param v Drugi wektor
	 * @param t Wspolczynnik interpolacji
	 * @return Zinterpolowany wektor
	 */
	Vector interpolate(const Vector &v, float t) const { return (*this)*t + v*(1.0f-t); }

	
	/**
	 * Oblicza iloczyn skalarny
	 *
	 * @param v Wektor
	 * @return Iloczyn skalarny
	 */
	float dotProduct(const Vector &v) const { return x*v.x + y*v.y + z*v.z; }


	/**
	 * Oblicza iloczyn wektorowy
	 *
	 * @param v Wektor
	 * @return Iloczyn wektorowy
	 */
	Vector crossProduct(const Vector &v) const { return Vector(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); }


	/**
	 * Oblicza kwadrat dlugosci wektora
	 *
	 * @return Kwadrat dlugosci wektora
	 */
	float getLengthSquared() const { return dotProduct(*this); }
	
	
	/**
	 * Oblicza dlugosc wektora
	 *
	 * @return Dlugosc wektora
	 */
	float getLength() const { return sqrt(getLengthSquared());}
	
	
	/**
	 * Ustawia dlugosc wektora.
	 * Kierunek wektora pozostaje bez zmian.
	 *
	 * @return Dlugosc wektora
	 */
	void setLength(float newLength) { normalize(); *this *= newLength; }


	/**
	 * Zwraca wektor jako tablice 3 liczb (wspolrzednych kartezjanskich)
	 *
	 * @return Tablica wspolrzednych
	 */
	operator const float*() const { return &x; }

	/**
	 * Zwraca element z tablicy 3 liczb (wspolrzednych kartezjanskich)
	 */
	float& operator[](int i) const { return ((float*)(&x))[i]; }


	// @{
	/**
	 * Pobiera wspolrzedna
	 */
	float getX() const { return x; }
	float getY() const { return y; }
	float getZ() const { return z; }
	// @}


	// @{
	/**
	 * Ustawia wspolrzedna
	 */
	void setX(float X) { x = X; }
	void setY(float Y) { y = Y; }
	void setZ(float Z) { z = Z; }
	// @}

};
